<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
<title>Threadpool</title>
<meta name="author" content="Christopher Arndt" />
<meta name="date" content="2008-11-19" />
<link rel="stylesheet" href="rest.css" type="text/css" />
</head>
<body>
<div class="document" id="threadpool">
<h1 class="title">Threadpool</h1>
<table class="docinfo" frame="void" rules="none">
<col class="docinfo-name" />
<col class="docinfo-content" />
<tbody valign="top">
<tr class="field"><th class="docinfo-name">Title:</th><td class="field-body">Easy to use object-oriented thread pool framework</td>
</tr>
<tr><th class="docinfo-name">Author:</th>
<td>Christopher Arndt</td></tr>
<tr><th class="docinfo-name">Version:</th>
<td>1.2.5</td></tr>
<tr><th class="docinfo-name">Date:</th>
<td>2008-11-19</td></tr>
<tr class="field"><th class="docinfo-name">License:</th><td class="field-body">MIT License</td>
</tr>
</tbody>
</table>
<!-- -*- coding: UTF-8 -*- -->
<div class="section" id="description">
<h1>Description</h1>
<p>A thread pool is an object that maintains a pool of worker threads to perform
time consuming operations in parallel. It assigns jobs to the threads
by putting them in a work request queue, where they are picked up by the
next available thread. This then performs the requested operation in the
background and puts the results in another queue.</p>
<p>The thread pool object can then collect the results from all threads from
this queue as soon as they become available or after all threads have
finished their work. It's then possible to define callbacks to handle
each result as it comes in.</p>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">This module is regarded as an extended example, not as a finished product.
Feel free to adapt it too your needs.</p>
</div>
</div>
<div class="section" id="basic-usage">
<h1>Basic usage</h1>
<pre class="literal-block">
&gt;&gt;&gt; pool = ThreadPool(poolsize)
&gt;&gt;&gt; requests = makeRequests(some_callable, list_of_args, callback)
&gt;&gt;&gt; [pool.putRequest(req) for req in requests]
&gt;&gt;&gt; pool.wait()
</pre>
<p>See the end of the module source code for a longer, annotated usage example.</p>
</div>
<div class="section" id="documentation">
<h1>Documentation</h1>
<p>You can view the API documentation, generated by epydoc, here:</p>
<blockquote>
<a class="reference external" href="http://chrisarndt.de/projects/threadpool/api/">API documentation</a></blockquote>
</div>
<div class="section" id="download">
<h1>Download</h1>
<p>You can download the latest version of this module here:</p>
<blockquote>
<a class="reference external" href="http://chrisarndt.de/projects/threadpool/download/">Download directory</a></blockquote>
<p>or see the colorized source code:</p>
<blockquote>
<a class="reference external" href="http://chrisarndt.de/projects/threadpool/threadpool.py.html">threadpool.py</a></blockquote>
<p>The documentation is also packaged in the distribution.</p>
</div>
<div class="section" id="discussion">
<h1>Discussion</h1>
<p>The basic concept and some code was taken from the book &quot;Python in a Nutshell&quot;
by Alex Martelli, copyright O'Reilly 2003, ISBN 0-596-00188-6, from section
14.5 &quot;Threaded Program Architecture&quot;. I wrapped the main program logic in the
<tt class="docutils literal"><span class="pre">ThreadPool</span></tt> class, added the <tt class="docutils literal"><span class="pre">WorkRequest</span></tt> class and the callback system
and tweaked the code here and there.</p>
<p>There are some other recipes in the Python Cookbook, that serve a similar
purpose. This one distinguishes itself by the following characteristics:</p>
<ul class="simple">
<li>Object-oriented, reusable design</li>
<li>Provides callback mechanism to process results as they are returned from the
worker threads.</li>
<li><tt class="docutils literal"><span class="pre">WorkRequest</span></tt> objects wrap the tasks assigned to the worker threads and
allow for easy passing of arbitrary data to the callbacks.</li>
<li>The use of the <tt class="docutils literal"><span class="pre">Queue</span></tt> class solves most locking issues.</li>
<li>All worker threads are daemonic, so they exit when the main programm exits,
no need for joining.</li>
<li>Threads start running as soon as you create them. No need to start or stop
them. You can increase or decrease the pool size at any time, superfluous
threads will just exit when they finish their current task.</li>
<li>You don't need to keep a reference to a thread after you have assigned the
last task to it. You just tell it: &quot;don't come back looking for work, when
you're done!&quot;</li>
<li>Threads don't eat up cycles while waiting to be assigned a task, they just
block when the task queue is empty (though they wake up every few seconds to
check whether they are dismissd).</li>
</ul>
<div class="section" id="notes">
<h2>Notes</h2>
<p>Due to the parallel nature of threads, you have to keep some things in mind:</p>
<ul class="simple">
<li>Do not use simultaneous threads for tasks were they compete for a single,
scarce resource (e.g. a harddisk or stdout). This will probably be slower
than taking a serialized approach.</li>
<li>If you call <tt class="docutils literal"><span class="pre">ThreadPool.wait()</span></tt> the main thread will block until _all_
results have arrived. If you only want to check for results that are available
immediately, use <tt class="docutils literal"><span class="pre">ThreadPool.poll()</span></tt>.</li>
<li>The results of the work requests are not stored anywhere. You should provide
an appropriate callback if you want to do so.</li>
</ul>
</div>
</div>
<div class="section" id="references">
<h1>References</h1>
<p>There are several other recipes similar to this module in the Python Cookbook,
for example:</p>
<ul class="simple">
<li><a class="reference external" href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/203871">http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/203871</a></li>
<li><a class="reference external" href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/196618">http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/196618</a></li>
<li><a class="reference external" href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302746">http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302746</a></li>
</ul>
</div>
<div class="section" id="news">
<h1>News</h1>
<!-- -*- coding: UTF-8 -*- -->
<dl class="docutils">
<dt>2008-11-19</dt>
<dd><ul class="first last simple">
<li>Update reference to &quot;Python In A Nutshell&quot; to second edition (suggested
by Alex Martelli).</li>
<li>Fixed typo in WorkerThread.run() (thanks to Nicholas Bollweg, Aaron
Levinson, Rogério Schneider, Grégory Starck for reporting).</li>
<li>Fixed missing first argument in call to Queue.get() in WorkerThread.run()
(thanks to Aaron Levinson for report).</li>
<li>added new argument 'do_join' to ThreadPool.dismissWorkers(). When True,
the method will perform Thread.join() on each thread after dismissing it.</li>
<li>Added joinAllDismissedWorkers method to ThreadPool to join dismissed
threads at a later time (thanks to Aaron Levinson for patch for these two
changes).</li>
</ul>
</dd>
<dt>2008-05-04</dt>
<dd><ul class="first last simple">
<li>'timeout' parameter of ThreadPool.putRequest now correctly defaults to 0
instead of None (thanks to Mads Sülau Jørgensen for bug report).</li>
<li>Added default exception handler callback (thanks to Moshe Cohen for the
patch).</li>
<li>Fixed locking issue that prevented worker threads from being dismissed
when no work requests are in the requests queue (thanks to Guillaume
Pratte for the bug report).</li>
<li>Add option for results queue size to ThreadPool (thanks to Krzysztof
Jakubczyk for the idea).</li>
<li>Changed name of reuquestQueue and resultsQueue attributes in WorkerThread
and ThreadPool to _requests_queue and _results_queue to be more consistent
and compliant with PEP 8 and properly indicate private nature.</li>
<li>Moved repository to Subversion.</li>
</ul>
</dd>
<dt>2008-05-03</dt>
<dd><ul class="first last simple">
<li>Updated homepage and download URL</li>
<li>Updated README</li>
<li>Enable packaging as an eggs with the use of setuptools</li>
<li>License changes to MIT License (Python license is only for code licensed
by the PSF)</li>
</ul>
</dd>
<dt>2006-06-23 1.2.3 (never announced)</dt>
<dd><ul class="first last simple">
<li>fixed typo in ThreadPool.putRequest() (reported by Jérôme Schneider)</li>
</ul>
</dd>
<dt>2006-05-19 1.2.2 (first release as a package)</dt>
<dd><ul class="first last simple">
<li>fixed wrong usage of isinstance in makeRequests()
Thanks to anonymous for bug report in comment on ASPN</li>
<li>added setup.py and created a proper distribution package</li>
<li>added timeout parameter to putRequest()</li>
</ul>
</dd>
</dl>
</div>
</div>
<div class="footer">
<hr class="footer" />
Generated on: 2008-11-19 17:43 UTC.

</div>
</body>
</html>
